﻿#region Legal

// Jimmy Zimmerman
// Team Mongoose
//
// END USER LICENSE AGREEMENT
// IMPORTANT - READ THIS CAREFULLY:  This End User License Agreement is a legal agreement
// between you (either an individual, business entity, currently active identity of an
// individual with Multiple Personality Disorder, octopus overlord, or otherworldly entity),
// and Team Mongoose, for the enclosed, components.
//
// By reading this document and/or installing this product, you agree to be bound by the
// terms of this EULA.
//
// Team Mongoose owns all copyright, trade secret, trademark, trade wars,
// patent, portent, and potential rights to these components.  Team Mongoose
// grants you the right to deploy the enclosed components.
//
// If you agree to the terms of this EULA, a license to use these components is granted to you.
//
// If you should happen to benefit from the enclosed components, then you are legally and
// contractually bound to thank us for it. Send your regards to jimmyzimms@hotmail.com.
//
// OTHER RIGHTS AND LIMITATONS
// You may not reverse-engineer, decompile, decode, disassemble, psycho-analyze, or otherwise
// attempt to find hidden meanings between the lines of this EULA; unless, of course, you should
// happen to find some, and they are funny.
//
// You may not translate this EULA or any part of the components into Ancient Sumerian.
//
// THESE COMPONENTS ARE PROVIDED “AS-IS” WITHOUT WARRANTY OF ANY KIND. ANY USE OF THE COMPONENTS
// CONTAINED IS AT YOUR OWN RISK. TEAM MONGOOSE DISCLAIM ALL WARRANTIES, EITHER
// EXPRESS OR IMPLIED, WITH RESPECT TO THE ACCURRACY AND CORRECTNESS OF THE COMPONENTS CONTAINED
// HEREIN. TEAM MONGOOSE DOES NOT WARRANT THAT THE COMPONENTS ARE FLAWLESS.
//
// REDISTRIBUTION AND USE IN SOURCE AND BINARY FORMS, WITH OR WITHOUT MODIFICATION, ARE PERMITTED
// PROVIDED THAT THE FOLLOWING CONDITIONS ARE MET:
// * REDISTRIBUTIONS OF SOURCE CODE MUST RETAIN THE ABOVE COPYRIGHT NOTICE
// * REDISTRIBUTIONS IN BINARY FORM MUST NOTE THE USE OF THE COMPONENT IN DOCUMENTATION AND/OR
//   OTHER MATERIALS PROVIDED WITH THE DISTRIBUTION.
// * NEITHER THE NAME OF TEAM MONGOOSE MAY BE USED TO ENDORES OR PROMOTE PRODUCTS
//   DERIVED FROM THIS SOFTWARE WITHOUT SPECIFIC PRIOR WRITTEN PERMISSION.
//
// IN NO EVENT SHALL TEAM MONGOOSE BE HELD LIABLE FOR INCIDENTAL, SPECIAL, INDIRECT,
// INCONSEQUENTIAL, UNBELIEVABLE, EXAGGERATED, VERBOSE, OR TYPICAL DAMAGES INCURRED WHILE USING
// THE ENCLOSED COMPONENTS.
//
// OUR STUFF ALWAYS WORKS - SOMETIMES.

#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Media.Imaging;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Mongoose.Games.BfgRoster.Tests
{
    [TestClass()]
    public class ShipClassTests
    {
        [TestMethod()]
        public void ConstructorShouldRequireName()
        {
            var tests = new Action[]
                            {
                                () => new ShipClass(null, VesselType.Orbital, new BitmapImage()),
                                () => new ShipClass(String.Empty, VesselType.Escort, new BitmapImage()),
                                () => new ShipClass(" ", VesselType.BattleCruiser, new BitmapImage())
                            };

            foreach (var test in tests)
            {
                try
                {
                    test();
                    Assert.Fail("Exception should have been thrown");
                }
                catch (ArgumentNullException exception)
                {
                    Assert.AreEqual("The value cannot be null, empty, or only contain whitespace characters.\r\nParameter name: name", exception.Message);
                }
            }
        }

        [TestMethod()]
        public void ConstructorShouldRequireImage()
        {
            try
            {
                new ShipClass("A ship", VesselType.Escort, null);
                Assert.Fail("Exception should have been thrown");
            }
            catch (ArgumentNullException exception)
            {
                Assert.AreEqual("Value cannot be null.\r\nParameter name: image", exception.Message);
            }
        }

        [TestMethod()]
        public void ConstructorShouldTrimName()
        {
            const String Name = " A name ";

            var shipClass = new ShipClass(Name, VesselType.Escort, new BitmapImage());

            Assert.AreEqual("A name", shipClass.Name);
        }

        [TestMethod()]
        public void ConstructorShouldSetPropertiesToExpectedValues()
        {
            const String Name = "A name";
            const VesselType VesselType = VesselType.Battleship;
            var image = new BitmapImage();

            var shipClass = new ShipClass(Name, VesselType, image);
            
            Assert.AreEqual(0, shipClass.Armaments.Count);
            Assert.IsFalse(shipClass.Armaments.IsReadOnly);
            Assert.IsNotNull(shipClass.Armor);
            Assert.AreEqual(5, shipClass.Armor.Bow);
            Assert.AreEqual(5, shipClass.Armor.Port);
            Assert.AreEqual(5, shipClass.Armor.Starbord);
            Assert.AreEqual(5, shipClass.Armor.Stern);
            Assert.AreSame(image, shipClass.Image);
            Assert.IsFalse(shipClass.IsLocked);
            Assert.AreEqual(Name, shipClass.Name);
            Assert.AreEqual(0, shipClass.Shields);
            Assert.AreEqual(0, shipClass.Speed);
            Assert.AreEqual(0, shipClass.TurnDegrees);
            Assert.AreEqual(0, shipClass.Turrets);
            Assert.AreEqual(VesselType, shipClass.VesselType);
        }

        [TestMethod()]
        public void ConstructorShouldSetDamageCapacityToVesselType()
        {
            var typeToCapacity = new Dictionary<VesselType, Int32>
                                                               {
                                                                   {VesselType.BattleCruiser, 8},
                                                                   {VesselType.Battleship, 10},
                                                                   {VesselType.Cruiser, 8},
                                                                   {VesselType.Escort, 1},
                                                                   {VesselType.GrandCruiser, 10},
                                                                   {VesselType.LightCruiser, 6},
                                                                   {VesselType.Orbital, 1}
                                                               };

            foreach (var item in typeToCapacity)
            {
                var shipClass = new ShipClass("A name", item.Key, new BitmapImage());
                Assert.AreEqual(item.Value, shipClass.DamageCapacity);
            }
        }

        [TestMethod()]
        public void StandardCapacityPropertyShouldHaveExpectedValues()
        {
            Dictionary<VesselType, Int32> expected = new Dictionary<VesselType, Int32>
                                                               {
                                                                   {VesselType.BattleCruiser, 8},
                                                                   {VesselType.Battleship, 10},
                                                                   {VesselType.Cruiser, 8},
                                                                   {VesselType.Escort, 1},
                                                                   {VesselType.GrandCruiser, 10},
                                                                   {VesselType.LightCruiser, 6},
                                                                   {VesselType.Orbital, 1}
                                                               };

            CollectionAssert.AreEqual(expected.Keys, (ICollection)ShipClass.StandardCapacities.Keys);
            CollectionAssert.AreEqual(expected.Values, (ICollection)ShipClass.StandardCapacities.Values);
        }

        [TestMethod()]
        public void CanSetProperties()
        {
            var newArmor = new ArmorRating(6);

            const String Name = "A name";
            const VesselType VesselType = VesselType.Battleship;

            var shipClass = new ShipClass(Name, VesselType, new BitmapImage());
            Assert.IsFalse(shipClass.IsLocked); // sanity check

            shipClass.Armaments.Add(new Loadout<Armament>(Bearing.Dorsal, new Armament("new armament 1", 1, 1)));
            Assert.AreEqual(1, shipClass.Armaments.Count);
            shipClass.Armor = newArmor;
            Assert.AreSame(newArmor, shipClass.Armor);
            shipClass.DamageCapacity = 20;
            Assert.AreEqual(20, shipClass.DamageCapacity);
            shipClass.Name = "a new name";
            Assert.AreEqual("a new name", shipClass.Name);
            shipClass.Ordinance.Add(new Loadout<Ordinance>(Bearing.Dorsal, new Ordinance("new ordinance1", 1, 1)));
            Assert.AreEqual(1, shipClass.Ordinance.Count);
            shipClass.Shields = 20;
            Assert.AreEqual(20, shipClass.Shields);
            shipClass.Speed = 50;
            Assert.AreEqual(50, shipClass.Speed);
            shipClass.TurnDegrees = 30;
            Assert.AreEqual(30, shipClass.TurnDegrees);
            shipClass.Turrets = 5;
            Assert.AreEqual(5, shipClass.Turrets);
        }

        [TestMethod()]
        public void CannotChangeLockedItem()
        {
            const String Name = "A name";
            const VesselType VesselType = VesselType.Battleship;

            var shipClass = new ShipClass(Name, VesselType, new BitmapImage());
            Assert.IsFalse(shipClass.IsLocked); // sanity check
            shipClass.Lock();
            Assert.IsTrue(shipClass.IsLocked);
            Assert.IsTrue(shipClass.Armaments.IsReadOnly);
            Assert.IsTrue(shipClass.Ordinance.IsReadOnly);

            var tests = new Action[]
                            {
                                () => shipClass.Armaments.Add(new Loadout<Armament>(Bearing.Dorsal, new Armament("new armament 1", 1, 1))),
                                () => shipClass.Armor = new ArmorRating(6),
                                () => shipClass.DamageCapacity = 20,
                                () => shipClass.Name = "a new name",
                                () => shipClass.Ordinance.Add(new Loadout<Ordinance>(Bearing.Dorsal, new Ordinance("new ordinance1", 1, 1))),
                                () => shipClass.Shields = 20,
                                () => shipClass.Speed = 50,
                                () => shipClass.TurnDegrees = 30,
                                () => shipClass.Turrets = 5
                            };
            foreach (var test in tests)
            {
                try
                {
                    test();
                    Assert.Fail("Exception should have been thrown");
                }
                catch (InvalidOperationException)
                {
                }
            }
        }
    }
}
